//
//  LLTTransition.swift
//  mmda
//
//  Created by 李陆涛 on 2018/8/8.
//  Copyright © 2018年 mmda. All rights reserved.
//

import UIKit

enum LLTTransitionAnimationType : Int {
    
    //----------- 系统 ------------
    case sysFade //淡入淡出
    
    case sysPushFromRight
    case sysPushFromLeft
    case sysPushFromTop
    case sysPushFromBottom //Push
    
    case sysRevealFromRight
    case sysRevealFromLeft
    case sysRevealFromTop
    case sysRevealFromBottom //揭开
    
    case sysMoveInFromRight
    case sysMoveInFromLeft
    case sysMoveInFromTop
    case sysMoveInFromBottom //覆盖
    
    case sysCubeFromRight
    case sysCubeFromLeft
    case sysCubeFromTop
    case sysCubeFromBottom //立方体
    
    case sysSuckEffect //吮吸
    
    case sysOglFlipFromRight
    case sysOglFlipFromLeft
    case sysOglFlipFromTop
    case sysOglFlipFromBottom //翻转
    
    case sysRippleEffect //波纹
    
    case sysPageCurlFromRight
    case sysPageCurlFromLeft
    case sysPageCurlFromTop
    case sysPageCurlFromBottom //翻页
    
    case sysPageUnCurlFromRight
    case sysPageUnCurlFromLeft
    case sysPageUnCurlFromTop
    case sysPageUnCurlFromBottom //反翻页
    
    case sysCameraIrisHollowOpen //开镜头
    
    case sysCameraIrisHollowClose //关镜头
}

enum LLTTransitionType {
    case pop
    case push
    case present
    case dismiss
}


class LLTTransition: NSObject  {
    
    let duration = 0.25
    
    var animationType:LLTTransitionAnimationType = .sysFade
    var transitionType:LLTTransitionType = .present
    
    var transitionContext : UIViewControllerContextTransitioning?
    
    var completionBlock:(()->())?
    
    
    func getSysTransition(_ type:LLTTransitionAnimationType) -> CATransition {
        
        let tranAnimation = CATransition()
        tranAnimation.duration = duration
        tranAnimation.delegate = self
        
        switch type {
            
        case .sysFade:
            
            tranAnimation.type = kCATransitionFade
        case .sysPushFromRight:
            
            tranAnimation.type = kCATransitionPush
            tranAnimation.subtype = kCATransitionFromRight
        case .sysPushFromLeft:
            
            tranAnimation.type = kCATransitionPush
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysPushFromTop:
            
            tranAnimation.type = kCATransitionPush
            tranAnimation.subtype = kCATransitionFromTop
        case .sysPushFromBottom:
            
            tranAnimation.type = kCATransitionPush
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysRevealFromRight:
            
            tranAnimation.type = kCATransitionReveal
            tranAnimation.subtype = kCATransitionFromRight
        case .sysRevealFromLeft:
            
            tranAnimation.type = kCATransitionReveal
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysRevealFromTop:
            
            tranAnimation.type = kCATransitionReveal
            tranAnimation.subtype = kCATransitionFromTop
        case .sysRevealFromBottom:
            
            tranAnimation.type = kCATransitionReveal
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysMoveInFromRight:
            
            tranAnimation.type = kCATransitionMoveIn
            tranAnimation.subtype = kCATransitionFromRight
        case .sysMoveInFromLeft:
            
            tranAnimation.type = kCATransitionMoveIn
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysMoveInFromTop:
            
            tranAnimation.type = kCATransitionMoveIn
            tranAnimation.subtype = kCATransitionFromTop
        case .sysMoveInFromBottom:
            
            tranAnimation.type = kCATransitionMoveIn
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysCubeFromRight:
            
            tranAnimation.type = "cube";
            tranAnimation.subtype = kCATransitionFromRight
        case .sysCubeFromLeft:
            
            tranAnimation.type = "cube";
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysCubeFromTop:
            
            tranAnimation.type = "cube";
            tranAnimation.subtype = kCATransitionFromTop
        case .sysCubeFromBottom:
            
            tranAnimation.type = "cube";
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysSuckEffect:
            
            tranAnimation.type = "suckEffect";
        case .sysOglFlipFromRight:
            
            tranAnimation.type = "oglFlip";
            tranAnimation.subtype = kCATransitionFromRight
        case .sysOglFlipFromLeft:
            
            tranAnimation.type = "oglFlip";
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysOglFlipFromTop:
            
            tranAnimation.type = "oglFlip";
            tranAnimation.subtype = kCATransitionFromTop
        case .sysOglFlipFromBottom:
            
            tranAnimation.type = "oglFlip";
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysRippleEffect:
            
            tranAnimation.type = "rippleEffect";
        case .sysPageCurlFromRight:
            
            tranAnimation.type = "pageCurl";
            tranAnimation.subtype = kCATransitionFromRight
        case .sysPageCurlFromLeft:
            
            tranAnimation.type = "pageCurl";
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysPageCurlFromTop:
            
            tranAnimation.type = "pageCurl";
            tranAnimation.subtype = kCATransitionFromTop
        case .sysPageCurlFromBottom:
            
            tranAnimation.type = "pageCurl";
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysPageUnCurlFromRight:
            
            tranAnimation.type = "pageUnCurl";
            tranAnimation.subtype = kCATransitionFromRight
        case .sysPageUnCurlFromLeft:
            
            tranAnimation.type = "pageUnCurl";
            tranAnimation.subtype = kCATransitionFromLeft
        case .sysPageUnCurlFromTop:
            
            tranAnimation.type = "pageUnCurl";
            tranAnimation.subtype = kCATransitionFromTop
        case .sysPageUnCurlFromBottom:
            
            tranAnimation.type = "pageUnCurl";
            tranAnimation.subtype = kCATransitionFromBottom
        case .sysCameraIrisHollowOpen:
            
            tranAnimation.type = "cameraIrisHollowOpen";
        case .sysCameraIrisHollowClose:
            
            tranAnimation.type = "cameraIrisHollowClose";
        }
        
        
        return tranAnimation
    }
    
    private func removeDelegate() {
        
        let fromVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.to)
        
        fromVC?.transitioningDelegate = nil;
        fromVC?.navigationController?.delegate = nil;
        toVC?.transitioningDelegate = nil;
        toVC?.navigationController?.delegate = nil;
    }
    
    private func transitionActionAnimation() {
        
        let fromVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.to)
        
        let fromTempView = fromVC?.view.snapshotView(afterScreenUpdates: true)
        let toTempView = toVC?.view.snapshotView(afterScreenUpdates: true)
        let containerView = transitionContext?.containerView
        
        containerView?.addSubview((fromVC?.view)!)
        containerView?.addSubview((toVC?.view)!)
        
        containerView?.bringSubview(toFront: (fromVC?.view)!)
        containerView?.bringSubview(toFront: (toVC?.view)!)
        
        let tranAnimation = getSysTransition(self.animationType)
        containerView?.layer.add(tranAnimation, forKey: nil)
        
        self.completionBlock = {
            
            [weak self] in
            guard let `self` = self else { return }
            
            if self.transitionContext?.transitionWasCancelled ?? false {
                self.transitionContext?.completeTransition(false)
            } else {
                
                self.transitionContext?.completeTransition(true)
            }
            
            fromTempView?.removeFromSuperview()
            toTempView?.removeFromSuperview()
            
        }
    }
    
    private func transitionBackAnimation() {
        
        let fromVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toVC = transitionContext?.viewController(forKey: UITransitionContextViewControllerKey.to)
        
        let fromTempView = fromVC?.view.snapshotView(afterScreenUpdates: true)
        let toTempView = toVC?.view.snapshotView(afterScreenUpdates: true)
        let containerView = transitionContext?.containerView
        
        containerView?.addSubview((fromVC?.view)!)
        containerView?.addSubview((toVC?.view)!)
        
        let tranAnimation = getSysTransition(LLTTransitionAnimationType(rawValue: self.animationType.rawValue + 1) ?? self.animationType)
        containerView?.layer.add(tranAnimation, forKey: nil)
        
        
        self.completionBlock = {
            
            [weak self] in
            guard let `self` = self else { return }
            
            if self.transitionContext?.transitionWasCancelled ?? false {
                self.transitionContext?.completeTransition(false)
            } else {
                
                self.transitionContext?.completeTransition(true)
            }
            fromTempView?.removeFromSuperview()
            toTempView?.removeFromSuperview()
            
        }
    }
}

extension LLTTransition : UIViewControllerAnimatedTransitioning {
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        
        return duration
    }
    
    func animationEnded(_ transitionCompleted: Bool) {
        
        if transitionCompleted {
            
            if transitionType == .dismiss || transitionType == .pop {
                
                self.removeDelegate()
            }
        }
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
        self.transitionContext = transitionContext
        
        switch transitionType {
        case .present,.push:
            
            transitionActionAnimation()
        case .dismiss,.pop:
            
            transitionBackAnimation()
        }
        
    }
}

extension LLTTransition : CAAnimationDelegate {
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        
        if flag {
            completionBlock?()
            completionBlock = nil
        }
    }
    
}

